#ifndef TINKLE_XMLNODE_H_INCLUDE
#define TINKLE_XMLNODE_H_INCLUDE

#include "XmlNode.h"

namespace tinkle{
	class XmlParser
	{
	public:	
		XmlParser();
		~XmlParser();

		//call back function for recving XmlNode
		typedef	 void (*XmlNodeCallback) (XmlNode*, void* extradata);


		enum parse_status {
			PARSER_NO_ERROR = 0,
			PARSER_NOT_CREATE,
			PARSER_CANT_CREATE,
			PARSER_BAD_PARSER
		};
		//register callback function, when the parser produce a node, it'll tell you
		//through @func.
		virtual void RegisterCallbackFunc(XmlNodeCallback func, void* extradata) {_notif = func; _notif_extra = extradata;};
		//unregister all callback function
		virtual void UnregisterCallbackFunc() {_notif = NULL;};
		
		//refresh the parser to restart a task
		virtual int Refresh(bool recoverymode = false);

		//you must ensure that chunk is encoded in UTF-8
		//if an error occur, it will return a non-zero value.
		virtual int Parse(const std::string& chunk);				
		virtual bool RecoveryMode() {return _r_mode;};

		


	protected:
		//You couldn't use this
		XmlParser(const XmlParser&);
		XmlParser& operator=(const XmlParser&);




	private:
		xmlNodePtr _p;
	protected:
		void _clear();
		//_sax_callback {
		static void On_Start_Element(void * ctx, const xmlChar * name, const xmlChar ** atts);
		static void On_End_Element(void* ctx, const xmlChar* name);
		static void On_Characters(void* ctx, const xmlChar* ch, int len);
		static void On_Warning(void* ctx, const char* fmt, ...);
		static void On_Error(void* ctx, const char* fmt, ...);
		//};

		static std::string _local_name(const xmlChar*);
		static bool _start_with_xmlns(const xmlChar* s);
		static std::string _prefix(const xmlChar*);


	protected:
		xmlParserCtxtPtr _c_txt;
		xmlSAXHandler _sax_hdl;

		bool _r_mode;

        
        //bad!!!!
        bool _refreshnextime;


		XmlNodeCallback _notif;
		void *_notif_extra;

		//stop parse when _badparser=true
		bool _badparser;

		XmlNode* _node;
		ElementPtr _curEle;

		ElementPtr  _stack[20];
		int _sp;
		void _stack_clear();
		ElementPtr _stack_pop();
		void _stack_push(ElementPtr &e);

		int _depth;
	};
}

#endif